package com.zhilianbao.leyaogo.view.widgets;

import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.annotation.DrawableRes;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.widget.AppCompatEditText;
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;

import com.zhilianbao.leyaogo.R;
import com.zhilianbao.leyaogo.utils.XToastUtils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * ClassName: AwsomeEditTextView <br>
 * Description: 自定义EditTextView 支持清除  显示隐藏密码<br>
 * Author: Cyarie <br>
 * Created: 2016/6/8 14:30 <br>
 * Update Time：<br>
 * Update Description：<br>
 */
public class AwesomeEditTextView extends AppCompatEditText {

    private boolean isShowingPassword = false;
    private Drawable drawablePwd;
    private Drawable drawableClear;
    private Rect bounds;
    private boolean leftToRight = true;
    private int tintColor = 0;
    private int style;
    private boolean alwaysShow;
    private int inputType;
    private boolean mHasFocus;

    @DrawableRes
    private int visibilityIndicatorShow = R.drawable.show_pwd;
    @DrawableRes
    private int visibilityIndicatorHide = R.drawable.hide_pwd;
    @DrawableRes
    private int clearDrawable = R.drawable.clear_icon;
    private boolean monospace;

    //过滤Emoji表情
    //输入表情前的光标位置
    private int cursorPos;
    //输入表情前EditText中的文本
    private String inputAfterText;
    //是否重置了EditText的内容
    private boolean resetText;
    private String mText;
    //是否禁掉表情
    private boolean filterEmoji;

    public AwesomeEditTextView(Context context) {
        super(context);
        init(null);
    }

    public AwesomeEditTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }

    public AwesomeEditTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(attrs);
    }

    private void init(AttributeSet attrs) {
        if (attrs != null) {
            TypedArray attrsArray = getContext().obtainStyledAttributes(attrs, R.styleable.AwesomeEditTextView);
            visibilityIndicatorShow = attrsArray.getResourceId(R.styleable.AwesomeEditTextView_aet_password_show_res, visibilityIndicatorShow);
            visibilityIndicatorHide = attrsArray.getResourceId(R.styleable.AwesomeEditTextView_aet_password_hide_res, visibilityIndicatorHide);
            clearDrawable = attrsArray.getResourceId(R.styleable.AwesomeEditTextView_aet_clear_res, clearDrawable);
            monospace = attrsArray.getBoolean(R.styleable.AwesomeEditTextView_aet_monospace, true);
            tintColor = attrsArray.getColor(R.styleable.AwesomeEditTextView_aet_tint_color, 0);
            style = attrsArray.getInt(R.styleable.AwesomeEditTextView_aet_style, 2);
            alwaysShow = attrsArray.getBoolean(R.styleable.AwesomeEditTextView_aet_always_show, false);
            inputType = attrsArray.getInt(R.styleable.AwesomeEditTextView_aet_input_type, 0);
            attrsArray.recycle();
        }
        leftToRight = isLeftToRight();
        isShowingPassword = false;
        //密码
        if (inputType == 1) {
            setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD, true);
        }
        //文本
        else if (inputType == 0) {
            setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_NORMAL, true);
        }
        //数字
        else if (inputType == 2) {
            setInputType(EditorInfo.TYPE_CLASS_NUMBER | EditorInfo.TYPE_NUMBER_VARIATION_NORMAL, true);
        }


        if (!monospace) {
            setTypeface(Typeface.DEFAULT);
        }

        if (!TextUtils.isEmpty(getText()) || alwaysShow) {
            if (style == 0) {
                showPasswordVisibilityIndicator(true);
            } else if (style == 1) {
                showClearVisibilityIndicator(true);
            } else {
                showPasswordVisibilityIndicator(false);
                showClearVisibilityIndicator(false);
            }

        }

        addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                if (filterEmoji) {
                    if (!resetText) {
                        cursorPos = AwesomeEditTextView.this.getSelectionEnd();
                        // 这里用s.toString()而不直接用s是因为如果用s，
                        // 那么，inputAfterText和s在内存中指向的是同一个地址，s改变了，
                        // inputAfterText也就改变了，那么表情过滤就失败了
                        inputAfterText = s.toString();
                    }
                }
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                if (s.length() > 0 && mHasFocus) {
                    if (style == 0) {
                        showPasswordVisibilityIndicator(true);
                    } else if (style == 1) {
                        showClearVisibilityIndicator(true);
                    }

                } else {
                    if (style == 0) {
                        if (alwaysShow)
                            return;
                        showPasswordVisibilityIndicator(false);
                    } else {
                        if (alwaysShow)
                            return;
                        showClearVisibilityIndicator(false);
                    }

                }

                //过滤Emoji表情
                if (filterEmoji) {

                    if (!resetText) {
                        mText = AwesomeEditTextView.this.getText().toString().trim();
                        if (mText == null || start >= mText.length()) {
                            return;
                        }
                        String input = mText.substring(start, mText.length());

                        if (isEmoji(input)) {
                            resetText = true;
                            XToastUtils.showShortToast("不支持输入Emoji表情符号");
                            //是表情符号就将文本还原为输入表情符号之前的内容
                            AwesomeEditTextView.this.setText(inputAfterText);
                            CharSequence text = AwesomeEditTextView.this.getText();
                            if (text instanceof Spannable) {
                                Spannable spanText = (Spannable) text;
                                Selection.setSelection(spanText, text.length());
                            }
                        }
                    } else {
                        resetText = false;
                    }
                }
            }

            @Override
            public void afterTextChanged(Editable s) {
            }
        });

        setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                mHasFocus = hasFocus;
                if (!hasFocus)
                    showClearVisibilityIndicator(false);
                if (style == 1 && hasFocus && !TextUtils.isEmpty(getText()))
                    showClearVisibilityIndicator(true);
            }
        });
    }

    //该正则可以有效过滤Emoji表情符号,无需判断count
    public boolean isEmoji(String string) {
        Pattern p = Pattern.compile("[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]",
                Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
        Matcher m = p.matcher(string);
        return m.find();
    }

    //设置是否禁掉表情
    public void setFilterEmoji(boolean filterEmoji){
        this.filterEmoji = filterEmoji;
    }
    private boolean isLeftToRight() {
        // If we are pre JB assume always LTR
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
            return true;
        }

        // Other methods, seemingly broken when testing though.
        // return ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL
        // return !ViewUtils.isLayoutRtl(this);

        Configuration config = getResources().getConfiguration();
        return !(config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
    }

    @Override
    public void setCompoundDrawables(Drawable left, Drawable top,
                                     Drawable right, Drawable bottom) {

        //keep a reference to the right drawable so later on touch we can check if touch is on the drawable
        if (leftToRight && right != null) {
            drawablePwd = right;
            drawableClear = right;
        } else if (!leftToRight && left != null) {
            drawablePwd = left;
            drawablePwd = left;
        }
        super.setCompoundDrawables(left, top, right, bottom);
    }

    public void setTintColor(@ColorInt int tintColor) {
        this.tintColor = tintColor;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        if (event.getAction() == MotionEvent.ACTION_UP && (drawablePwd != null || drawableClear != null)) {
            bounds = style == 0 ? drawablePwd.getBounds() : drawableClear.getBounds();
            final int x = (int) event.getX();

            //check if the touch is within bounds of drawableEnd icon
            if ((leftToRight && (x >= (this.getWidth() - bounds.width() - this.getPaddingRight()))) ||
                    (!leftToRight && (x <= (this.getLeft() + bounds.width() - this.getPaddingLeft())))) {
                if (style == 0) {
                    togglePasswordVisibility();
                } else if (style == 1 && mHasFocus) {
                    this.setText("");
                    showClearVisibilityIndicator(false);
                }
                if (mOnDrawableClickListener != null) {
                    mOnDrawableClickListener.onDrawableClick();
                }
                //use this to prevent the keyboard from coming up
                event.setAction(MotionEvent.ACTION_CANCEL);
            }
        }
        return super.onTouchEvent(event);
    }

    public interface OnDrawableClickListener {
        void onDrawableClick();
    }

    private OnDrawableClickListener mOnDrawableClickListener;

    public void setOnDrawableClickListener(OnDrawableClickListener mOnDrawableClickListener) {
        this.mOnDrawableClickListener = mOnDrawableClickListener;
    }

    private void showPasswordVisibilityIndicator(boolean show) {
        if (show) {
            Drawable original = isShowingPassword ?
                    ContextCompat.getDrawable(getContext(), visibilityIndicatorShow) :
                    ContextCompat.getDrawable(getContext(), visibilityIndicatorHide);
            original.mutate();

            if (tintColor == 0) {
                setCompoundDrawablesWithIntrinsicBounds(leftToRight ? null : original, null, leftToRight ? original : null, null);
            } else {
                Drawable wrapper = DrawableCompat.wrap(original);
                DrawableCompat.setTint(wrapper, tintColor);
                setCompoundDrawablesWithIntrinsicBounds(leftToRight ? null : wrapper, null, leftToRight ? wrapper : null, null);
            }
        } else {
            setCompoundDrawables(null, null, null, null);
        }
    }


    private void showClearVisibilityIndicator(boolean show) {
        if (show) {
            Drawable original = ContextCompat.getDrawable(getContext(), clearDrawable);
            original.mutate();
            if (tintColor == 0) {
                setCompoundDrawablesWithIntrinsicBounds(leftToRight ? null : original, null, leftToRight ? original : null, null);
            } else {
                Drawable wrapper = DrawableCompat.wrap(original);
                DrawableCompat.setTint(wrapper, tintColor);
                setCompoundDrawablesWithIntrinsicBounds(leftToRight ? null : wrapper, null, leftToRight ? wrapper : null, null);
            }
        } else {
            setCompoundDrawables(null, null, null, null);
        }
    }

    private void togglePasswordVisibility() {
        if (isShowingPassword) {
            setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD, true);
        } else {
            setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD, true);
        }
        isShowingPassword = !isShowingPassword;
        showPasswordVisibilityIndicator(true);
    }

    @Override
    protected void finalize() throws Throwable {
        drawablePwd = null;
        drawableClear = null;
        bounds = null;
        super.finalize();
    }


    private void setInputType(int inputType, boolean keepState) {
        int selectionStart = -1;
        int selectionEnd = -1;
        if (keepState) {
            selectionStart = getSelectionStart();
            selectionEnd = getSelectionEnd();
        }
        setInputType(inputType);
        if (keepState) {
            setSelection(selectionStart, selectionEnd);
        }
    }


    public
    @DrawableRes
    int getVisiblityIndicatorShow() {
        return visibilityIndicatorShow;
    }

    public void setVisiblityIndicatorShow(@DrawableRes int visibilityIndicatorShow) {
        this.visibilityIndicatorShow = visibilityIndicatorShow;
    }

    public
    @DrawableRes
    int getVisibilityIndicatorHide() {
        return visibilityIndicatorHide;
    }

    public void setVisibilityIndicatorHide(@DrawableRes int visibilityIndicatorHide) {
        this.visibilityIndicatorHide = visibilityIndicatorHide;
    }

    /**
     * @return true if the password is visible | false if hidden
     */
    public boolean isShowingPassword() {
        return isShowingPassword;
    }

    public int getClearDrawable() {
        return clearDrawable;
    }

    public void setClearDrawable(@DrawableRes int clearDrawable) {
        this.clearDrawable = clearDrawable;
        showClearVisibilityIndicator(true);
    }

    public void setDrawableClearVisible(boolean visible) {
        showClearVisibilityIndicator(visible);
    }
}
